﻿using System;
using System.Collections.Generic;
using Internal.KuiHuaBaoDian.Services.Battle.StateMachine;
using KuiHuaBaoDian.Services.Battle.Entity;
using KuiHuaBaoDian.Services.Battle.StateMachine;
using UnityEngine;

namespace KuiHuaBaoDian.Services.Battle.StateMachine {

    /// <summary>
    /// 指定一组<see cref="UnityEngine.GameObject"/>进行显示的状态机
    /// </summary>
    public interface IBattleEntityStateMachine_SwapGameObject : IBattleEntityStateMachine {

        /// <summary>
        /// 显示状态提供者
        /// </summary>
        public interface IStateProvider {

            public const int INDEX_IDLE = 0;

            public const int INDEX_MOVE = 1;

            public const int INDEX_ATTACK = 2;

            public const int INDEX_DIE = 3;

            /// <summary>
            /// 闲置
            /// </summary>
            GameObject Idle { get; }

            /// <summary>
            /// 移动
            /// </summary>
            GameObject Move { get; }

            /// <summary>
            /// 攻击
            /// </summary>
            GameObject Attack { get; }

            /// <summary>
            /// 死亡
            /// </summary>
            GameObject Die { get; }
        }
    }

    [Implement(typeof(IBattleEntityStateMachine_SwapGameObject))]
    internal sealed class KHBD_BattleEntityStateMachine_SwapGameObject : KHBD_Object, IBattleEntityStateMachine_SwapGameObject, IBattleEntityStateMachineInternal_SwapGameObject {

        private IBattleEntityAssetVehicle<IBattleEntityStateMachine_SwapGameObject.IStateProvider> m_StateVehicle;
        private IDictionary<BattleEntityState, GameObject> m_StateGameObjectDictionary;

        public BattleEntityState State { get; set; }
        private BattleEntityState m_LastState;

        private bool m_ForceRefreshState;
        public bool IsStateChanged => State != m_LastState || m_ForceRefreshState;

        public bool IsInitialized => m_StateGameObjectDictionary != null;

        private IDictionary<BattleEntityState, ParticleSystem[]> m_StateParticleSystemsDictionary = new Dictionary<BattleEntityState, ParticleSystem[]>();

        private float m_PlaySpeed;

        void IBattleEntityStateMachineInternal_SwapGameObject.Initialize(IBattleEntityAssetVehicle<IBattleEntityStateMachine_SwapGameObject.IStateProvider> stateVehicle) {
            UnityEngine.Assertions.Assert.IsNotNull(stateVehicle);

            m_StateVehicle = stateVehicle;
            m_StateVehicle.Loaded += OnStateVehicleLoaded;
            OnStateVehicleLoaded();
        }

        protected override void Dispose() {
            m_StateParticleSystemsDictionary = null;
            m_StateGameObjectDictionary = null;
            m_StateVehicle = null;
        }

        private void OnStateVehicleLoaded() {
            if (m_StateVehicle.Content == null) {
                return;
            }
            m_StateGameObjectDictionary = new Dictionary<BattleEntityState, GameObject>() {
                { BattleEntityState.Idle, m_StateVehicle.Content.Idle },
                { BattleEntityState.Move, m_StateVehicle.Content.Move },
                { BattleEntityState.Attack, m_StateVehicle.Content.Attack },
                { BattleEntityState.Die, m_StateVehicle.Content.Die },
            };
            foreach (var kv in m_StateGameObjectDictionary) {
                kv.Value.SetActive(m_LastState != BattleEntityState.Unknown && kv.Key == m_LastState);
            }
            m_ForceRefreshState = true;
            Play(m_PlaySpeed);
        }

        public void Play(float speed) {
            m_PlaySpeed = speed;

            if (!IsInitialized) {
                return;
            }
            if (State == BattleEntityState.Unknown) {
                return;
            }

            bool isStateChanged = IsStateChanged || m_ForceRefreshState;
            m_ForceRefreshState = false;
            if (isStateChanged) {
                foreach (var kv in m_StateGameObjectDictionary) {
                    kv.Value.SetActive(kv.Key == State);
                }
                m_LastState = State;
            }

            if (!m_StateParticleSystemsDictionary.TryGetValue(State, out var particleSystems) && m_StateGameObjectDictionary.TryGetValue(State, out var state)) {
                particleSystems = state.GetComponentsInChildren<ParticleSystem>(true);
                m_StateParticleSystemsDictionary[State] = particleSystems;
            }

            if (particleSystems?.Length > 0) {
                foreach (var particleSystem in particleSystems) {
                    if (isStateChanged) {
                        particleSystem.Stop(false, ParticleSystemStopBehavior.StopEmitting);
                        particleSystem.Play(false);
                    }
                    var mainModule = particleSystem.main;
                    mainModule.simulationSpeed = speed;
                }
            }
        }
    }
}

namespace Internal.KuiHuaBaoDian.Services.Battle.StateMachine {

    public interface IBattleEntityStateMachineInternal_SwapGameObject : IBattleEntityStateMachine, IDisposable {

        void Initialize(IBattleEntityAssetVehicle<IBattleEntityStateMachine_SwapGameObject.IStateProvider> stateVehicle);
    }
}